package com.chaos.framework.starter.base;


import cn.hutool.core.util.IdUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.excel.EasyExcel;
import com.chaos.framework.model.constant.Constants;
import com.chaos.framework.model.dto.DTO;
import com.chaos.framework.model.dto.ID;
import com.chaos.framework.model.dto.MU;
import com.chaos.framework.model.dto.page.PageList;
import com.chaos.framework.model.dto.result.data.BooleanResult;
import com.chaos.framework.model.dto.result.data.DataResult;
import com.chaos.framework.model.dto.result.data.StringResult;
import com.chaos.framework.model.dto.result.list.ListResult;
import com.chaos.framework.model.dto.result.page.PageResult;
import com.chaos.framework.model.enums.ResultEnum;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.MDC;
import org.springframework.core.io.InputStreamResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;

import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @author Jacky
 */
@Slf4j
public abstract class BaseController<T extends DTO> {
    @Resource
    protected HttpServletRequest request;
    @Resource
    protected HttpServletResponse response;


    public DataResult<T> ok(T data) {
        return DataResult.ok(data);
    }

    public DataResult<T> error(ResultEnum resultEnum) {
        return DataResult.error(resultEnum);
    }

    public DataResult<T> error(Integer errorCode, String msg) {
        return DataResult.error(errorCode, msg);
    }

    public DataResult<T> error(Integer errorCode, String msg, T data) {
        return DataResult.error(errorCode, msg, data);
    }

    public BooleanResult booleanResult(Boolean data) {
        return BooleanResult.ok(data);
    }

    public StringResult stringResult(String data) {
        return StringResult.ok(data);
    }

    public DataResult<T> dataResult(T data) {
        return DataResult.ok(data);
    }

    public DataResult<ID> dataResult(ID id) {
        return new DataResult<>(ResultEnum.OK.getCode(), ResultEnum.OK.getDefaultMsg(), id);
    }

    public DataResult<MU> dataResult(MU mu) {
        return new DataResult<>(ResultEnum.OK.getCode(), ResultEnum.OK.getDefaultMsg(), mu);
    }

    public DataResult<Boolean> dataResult(Boolean data) {
        return new DataResult<>(ResultEnum.OK.getCode(), ResultEnum.OK.getDefaultMsg(), data);
    }

    public DataResult<String> dataResult(String data) {
        return new DataResult<>(ResultEnum.OK.getCode(), ResultEnum.OK.getDefaultMsg(), data);
    }

    public DataResult<Integer> dataResult(Integer data) {
        return new DataResult<>(ResultEnum.OK.getCode(), ResultEnum.OK.getDefaultMsg(), data);
    }

    public DataResult<Double> dataResult(Double data) {
        return new DataResult<>(ResultEnum.OK.getCode(), ResultEnum.OK.getDefaultMsg(), data);
    }

    public DataResult<Float> dataResult(Float data) {
        return new DataResult<>(ResultEnum.OK.getCode(), ResultEnum.OK.getDefaultMsg(), data);
    }

    public DataResult<List<T>> dataResult(List<T> data) {
        return new DataResult<>(ResultEnum.OK.getCode(), ResultEnum.OK.getDefaultMsg(), data);
    }

    public ListResult<T> listResult(List<T> list) {
        return ListResult.ok(list);
    }

    public PageResult<T> pageResult(PageList<T> pageList) {
        return PageResult.ok(pageList);
    }

    public Long getUserId() {
        return Long.valueOf(request.getHeader("userId"));
    }

    public Long getUsername() {
        return Long.valueOf(request.getHeader("username"));
    }

    public Long getAdminId() {
        return Long.valueOf(request.getHeader("adminId"));
    }

    public Long getTenantId() {
        return Long.valueOf(request.getHeader("tenantId"));
    }

    public Long getClientId() {
        return Long.valueOf(request.getHeader("clientId"));
    }

    public String getTraceId() {
        String traceId = request.getHeader(Constants.TRACE_ID);
        if (StringUtils.isEmpty(traceId)) {
            traceId = IdUtil.simpleUUID();
            MDC.put(Constants.TRACE_ID, traceId);
        }
        return traceId;
    }

    public String json(Object data) {
        return JSONUtil.toJsonStr(data);
    }

    public void exportExecl(List<T> list, Class<T> target) throws IOException {
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + "data.xlsx");
        EasyExcel.write(response.getOutputStream(), target).sheet("sheet1").doWrite(list);
    }

    public ResponseEntity<InputStreamResource> exportZip(Map<String, ArrayList<T>> tagMap, Class<T> target) throws IOException {
        ByteArrayOutputStream zipOutputStream = new ByteArrayOutputStream();
        ZipArchiveOutputStream zipArchiveOutputStream = new ZipArchiveOutputStream(zipOutputStream);

        tagMap.keySet().forEach(key -> {
            String filePath = "./xlsx/" + key + ".xlsx";
            List<T> list = tagMap.get(key);
            EasyExcel.write(filePath, target).sheet(key).doWrite(list);
            try {
                zipArchiveOutputStream.putArchiveEntry(new ZipArchiveEntry(key));
                zipArchiveOutputStream.write(Files.readAllBytes(Paths.get(filePath)));
                zipArchiveOutputStream.closeArchiveEntry();
            } catch (Exception e) {
                log.error("addFileToZip error", e);
            }
        });

        zipArchiveOutputStream.close();
        HttpHeaders headers = new HttpHeaders();
        headers.add("Content-Disposition", "attachment; filename=exportZip.zip");
        InputStream is = new ByteArrayInputStream(zipOutputStream.toByteArray());
        return ResponseEntity.ok().headers(headers).contentType(MediaType.APPLICATION_OCTET_STREAM).body(new InputStreamResource(is));
    }


}
